Professional Documents
Culture Documents
Alexander Dymo
RailsConf 2009
http://en.oreilly.com/rails2009/public/schedule/detail/8615
www.acunote.com
What Am I Optimizing? Project Management and Scrum Software
http://en.oreilly.com/rails2009/public/schedule/detail/8615
Acunote www.acunote.com
● ~3700 customers
● Hosted on Engine Yard
● Hosted on Customers' Servers
● nginx + mongrel
● PostgreSQL
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 2 / 84
Performance Degradation Over Time Project Management and Scrum Software
300
Request Time (on development box), %
150
100
April 2008 May 2008 June 2008 July 2008
Performance Optimization!
What to optimize?
Development?
Development
AND Production
How to optimize?
Three rules of
performance optimization
1. Measure!
...the universal experience of
programmers who have been using
measurement tools has been that
their intuitive guesses fail...
Knuth
● Development
– Ruby code
– Rails code
– Database queries
– Alternative Ruby
● Production
– Shared filesystems and databases
– Live debugging
– Load balancing
● Frontend
– HTTP
– Javascript
– Internet Explorer
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 14 / 84
Optimizing Ruby: Date Class Project Management and Scrum Software
● Development
– Ruby code
– Rails code
– Database queries
– Alternative Ruby
● Production
– Shared filesystems and databases
– Live debugging
– Load balancing
● Frontend
– HTTP
– Javascript
– Internet Explorer
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 19 / 84
Optimizing Rails: Preloading Associations Project Management and Scrum Software
class Foo
belongs_to :bar
end
class Bar
end
class Foo
belongs_to :bar
preloadable_association :bar
end
foos = Foo.find_by_sql('
select * from foos
left outer join
(select id as preloaded_bar_id,
name as preloaded_bar_name
from bars) as bars
on foos.bar_id = bars.preloaded_bar_id')
foos.first.bar #no extra SQL query!
list.rhtml
_object.rhtml _object.rhtml
_object.rhtml _object.rhtml
list.rhtml
_object.rhtml _object.rhtml
_object.rhtml _object.rhtml
1.2x
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 25 / 84
Things To Optimize Project Management and Scrum Software
● Development
– Ruby code
– Rails code
– Database queries
– Alternative Ruby
● Production
– Shared filesystems and databases
– Live debugging
– Load balancing
● Frontend
– HTTP
– Javascript
– Internet Explorer
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 26 / 84
Optimizing Database Project Management and Scrum Software
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------
Merge IN Join (actual time=0.096..576.704 rows=55363 loops=1)
Merge Cond: (issues.id = tags_issues.issue_id)
-> Index Scan using issues_pkey on issues (actual time=0.027..270.557 rows=229991 loops=1)
-> Index Scan using tags_issues_issue_id_key on tags_issues (actual time=0.051..73.903 rows=70052loops=1)
Total runtime: 605.274 ms
explain analyze select * from issues where id = any( array( (select issue_id from tags_issues) ) );
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on issues (actual time=247.358..297.932 rows=55363 loops=1)
Recheck Cond: (id = ANY ($0))
InitPlan
-> Seq Scan on tags_issues (actual time=0.017..51.291 rows=70052 loops=1)
-> Bitmap Index Scan on issues_pkey (actual time=246.589..246.589 rows=70052 loops=1)
Index Cond: (id = ANY ($0))
Total runtime: 325.205 ms
2x!
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 29 / 84
Database Optimization: PostgreSQL Tips Project Management and Scrum Software
select *,
Issues (select notes.author from notes
id serial where notes.issue_id = issues.id
name varchar ) as note_authors
org_id integer from issues
where org_id = 1
Notes
id serial select *,
name varchar (select notes.author from notes
issue_id integer where notes.issue_id = issues.id and org_id = 1
org_id integer ) as note_authors
from issues
where org_id = 1
Everybody says
"JRuby and Ruby 1.9 are faster"
In short, YES!
In short, YES!
What is faster?
Why faster?
● Development
– Ruby code
– Rails code
– Database queries
– Alternative Ruby
● Production
– Shared filesystems and databases
– Live debugging
– Load balancing
● Frontend
– HTTP
– Javascript
– Internet Explorer
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 43 / 84
Optimizing For Shared Environment Project Management and Scrum Software
Solutions:
● buy more memory
● optimize memory
● set memory limits for mongrels (with monit)
Solutions:
optimize for the cold state
sudo echo 3 | sudo tee /proc/sys/vm/drop_caches
push down SQL conditions
We used
a) filesystem store for fragment caching
b) expire_fragment(regexp)
● Development
– Ruby code
– Rails code
– Database queries
– Alternative Ruby
● Production
– Shared filesystems and databases
– Live debugging
– Load balancing
● Frontend
– HTTP
– Javascript
– Internet Explorer
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 52 / 84
Live Debugging Project Management and Scrum Software
● Development
– Ruby code
– Rails code
– Database queries
– Alternative Ruby
● Production
– Shared filesystems and databases
– Live debugging
– Load balancing
● Frontend
– HTTP
– Javascript
– Internet Explorer
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 54 / 84
Load Balancing Project Management and Scrum Software
per-process queues
Rails App 1 1 2
Rails App 2 1 2 3
Rails App 3 1 2 3
Rails App 1
Rails App 2 1 2 3 4 5
Rails App 3
Rails App 1 1
Rails App 2 1 2
Rails App 3 1 2 3
● Development
– Ruby code
– Rails code
– Database queries
– Alternative Ruby
● Production
– Shared filesystems and databases
– Live debugging
– Load balancing
● Frontend
– HTTP
– Javascript
– Internet Explorer
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 60 / 84
Optimize For The User: HTTP Project Management and Scrum Software
Things to consider:
● Gzip HTML, CSS and JS
● Minify JS
● Collect JS and CSS
(javascript_include_tag :all, :cache => true)
● Far future expires headers for JS, CSS, images
● Sprites
● Cache-Control: public
● everything else YSlow tells you
● Development
– Ruby code
– Rails code
– Database queries
– Alternative Ruby
● Production
– Shared filesystems and databases
– Live debugging
– Load balancing
● Frontend
– HTTP
– Javascript
– Internet Explorer
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 62 / 84
Optimize Frontend: Javascript Project Management and Scrum Software
● Development
– Ruby code
– Rails code
– Database queries
– Alternative Ruby
● Production
– Shared filesystems and databases
– Live debugging
– Load balancing
● Frontend
– HTTP
– Javascript
– Internet Explorer
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 67 / 84
Optimize Frontend: IE Project Management and Scrum Software
Unsurprisingly...
IE is also slow!
profiler in IE8
fast in IE => fast everywhere else!
def test_sprint_rendering
login_with users(:user), "user"
end
def test_queries
queries = track_queries do
get :index
end
assert_equal queries, [
"Foo Load",
"Bar Load",
"Event Create"
]
end
module ActiveSupport
class BufferedLogger
attr_reader :tracked_queries
def tracking=(val)
@tracked_queries = []
@tracking = val
end
def debug_with_tracking(message)
@tracked_queries << $1 if @tracking && message =~ /3[56]\;1m(.* (Load|Create|
Update|Destroy)) \(/
debug_without_tracking(message)
end
alias_method_chain :debug, :tracking
end
end
class ActiveSupport::TestCase
def track_queries(&block)
RAILS_DEFAULT_LOGGER.tracking = true
yield
result = RAILS_DEFAULT_LOGGER.tracked_queries
RAILS_DEFAULT_LOGGER.tracking = false
result
end
end
Reinstall ruby-prof
Use RUBY_PROF_MEASURE_MODE=memory
when running ruby-prof
http://blog.pluron.com/2008/02/memory-profilin.html
Alexander Dymo • Advanced Performance Optimization of Rails Applications • RailsConf 2009 81 / 84
Remember! Project Management and Scrum Software
Thanks!
Slides for this talk:
http://en.oreilly.com/rails2009/public/schedule/detail/8615